﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Web;
using BaseLib.Helper;

namespace BaseData.Exts
{
    public static class DataTableExt
    {
        /// <summary>
        /// 返回枚举项的描述信息。
        /// </summary>
        /// <param name="value">要获取描述信息的枚举项。</param>
        /// <param name="isTop"></param>
        /// <returns>枚举想的描述信息。</returns>
        public static string GetDescription(this Enum value, bool isTop = false)
        {
            var enumType = value.GetType();
            DescriptionAttribute attr = null;
            if (isTop)
                attr = (DescriptionAttribute)Attribute.GetCustomAttribute(enumType, typeof(DescriptionAttribute));
            else
            {
                // 获取枚举常数名称。
                var name = Enum.GetName(enumType, value);
                if (name == null) return string.Empty;
                // 获取枚举字段。
                var fieldInfo = enumType.GetField(name);
                // 获取描述的属性。
                if (fieldInfo != null) attr = Attribute.GetCustomAttribute(fieldInfo, typeof(DescriptionAttribute), false) as DescriptionAttribute;
            }
            return attr != null && !string.IsNullOrEmpty(attr.Description) ? attr.Description : string.Empty;
        }
        public static T ToEnumsDefault<T>(this Enum obj, int def = 0)
        {
            try
            {
                return (T)Enum.ToObject(typeof(T), obj);
            }
            catch (Exception)
            {
                return (T)Enum.ToObject(typeof(T), 0);
            }
        }
        public static T ToEnumsDefault<T>(this Enum obj, T def)
        {
            try
            {
                var v = Convert.ToInt32((T)Enum.ToObject(typeof(T), obj));
                if (v == 0)
                    return def;
                return (T)Enum.ToObject(typeof(T), obj);
            }
            catch (Exception)
            {
                return def;
            }
        }

        public static String TToAssembly<Ancp>(this Ancp t)
        {
            return t.GetType().FullName + "," + t.GetType().Assembly.FullName;
        }

        public static DataTable IListConvertToDataTable(this IEnumerable<DataTableClass.Convert> items)
        {
            var dtNew = new DataTable();
            foreach (var item in items)
            {
                // Type t1 = Type.GetType(t.table, true);
                // object temp = System.Activator.CreateInstance(t1);
                var ts = Type.GetType(item.Assembly, true);
                foreach (var field in ts.GetProperties())
                {
                    if (item.skip != null && item.skip.Contains(field.Name)) continue; // skip某些字段
                    if (item.take != null && !item.take.Contains(field.Name)) continue; // take某些字段
                    var columnType = field.PropertyType;
                    if ((columnType.IsGenericType) && (columnType.GetGenericTypeDefinition() == typeof(Nullable<>))) columnType = columnType.GetGenericArguments()[0];
                    // var c = field.Name.Substring(0, 1).ToCharArray();
                    // if (c[0] < 'a' || c[0] > 'z')
                    dtNew.Columns.Add(new DataColumn(item.fix + field.Name, columnType));
                }
            }
            return dtNew;
        }

        public static DataTable IListFillDataRow<T>(this IEnumerable<T> ts, DataTableClass.Fills paras)
        {
            foreach (var t in ts)
            {
                var dr = paras.table.NewRow();
                foreach (var field in t.GetType().GetProperties())
                {
                    if (paras.skip != null && paras.skip.Contains(field.Name)) continue; // skip某些字段
                    if (paras.take != null && !paras.take.Contains(field.Name)) continue; // take某些字段
                    // var c = field.Name.Substring(0, 1).ToCharArray();
                    // if (c[0] < 'a' || c[0] > 'z')
                    dr[field.Name] = field.GetValue(t, null) ?? DBNull.Value;
                    // dr["IsLeaf"] = hasLeaf;
                    // dr["NodeCount"] = nodeCount;
                    // dr["NodeInfoCount"] = infoCount;
                }
                paras.table.Rows.Add(dr);
            }
            return paras.table;
        }

        public static void IListFillDataRow<T>(this T t, DataTableClass.Fill paras)
        {
            var conditon = paras.key + "='" + paras.value + "'";
            var drs = paras.table.Select(conditon);
            foreach (var dr in drs)
            {
                foreach (var field in t.GetType().GetProperties())
                {
                    if (paras.skip != null && paras.skip.Contains(field.Name)) continue; // skip某些字段
                    if (paras.take != null && !paras.take.Contains(field.Name)) continue; // take某些字段
                    // var c = field.Name.Substring(0, 1).ToCharArray();
                    // if (c[0] < 'a' || c[0] > 'z')
                    dr[paras.fix + field.Name] = field.GetValue(t, null) ?? DBNull.Value;
                    // dr["IsLeaf"] = hasLeaf;
                    // dr["NodeCount"] = nodeCount;
                    // dr["NodeInfoCount"] = infoCount;
                }
            }
        }

        public static DataTable TToDataTable<T>(this T t, string[] skip) where T : new()
        {
            return TToDataTable<T>(t, "Info", skip);
        }

        public static DataTable TToDataTable<T>(this T t, string fieldFix = "Info") where T : new()
        {
            return TToDataTable<T>(t, fieldFix, null);
        }

        public static DataTable TToDataTable<T>(this T list, string fieldFix, string[] skip) where T : new()
        {
            var dt = new DataTable();
            foreach (var field in typeof(T).GetProperties())
            {
                if (skip != null && skip.Contains(field.Name)) continue; // 跳过某些字段
                var columnType = field.PropertyType;
                if ((columnType.IsGenericType) && (columnType.GetGenericTypeDefinition() == typeof(Nullable<>))) columnType = columnType.GetGenericArguments()[0];
                // var c = field.Name.Substring(0, 1).ToCharArray();
                // if (c[0] < 'a' || c[0] > 'z')
                dt.Columns.Add(new DataColumn(fieldFix + field.Name, columnType));
            }
            return dt;
        }

        public static DataRow TFillDataRow<T>(this T t, DataRow dr, string[] skip) where T : new()
        {
            return TFillDataRows<T>(t, dr, "Info", skip);
        }

        public static DataRow TFillDataRow<T>(this T t, DataRow dr, string fieldFix = "Info") where T : new()
        {
            return TFillDataRows<T>(t, dr, fieldFix, null);
        }

        public static DataRow TFillDataRows<T>(this T t, DataRow dr, string fieldFix, string[] skip, bool IsLeaf = false, bool IsLast = false, int NodeLayer = 0, int nodeCount = 0, int infoCount = 0) where T : new()
        {
            foreach (var field in typeof(T).GetProperties())
            {
                if (skip != null && skip.Contains(field.Name)) continue; // 跳过某些字段
                // var c = field.Name.Substring(0, 1).ToCharArray();
                // if (c[0] < 'a' || c[0] > 'z')
                dr[fieldFix + field.Name] = field.GetValue(t, null) ?? DBNull.Value;
            }
            if (String.Compare(fieldFix, "Node", StringComparison.Ordinal) != 0) return dr;
            dr["IsLeaf"] = IsLeaf;
            dr["IsLast"] = IsLast;
            dr["NodeLayer"] = NodeLayer;
            dr["NodeCount"] = nodeCount;
            dr["InfoCount"] = infoCount;
            return dr;
        }

        public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> src, Func<TSource, TKey> key)
        {
            var hashSet = new HashSet<TKey>();
            return src.Where(item => hashSet.Add(key(item)));
        }

        public static DataTable ToDataTable<T>(this IEnumerable<T> list, CreateRowDelegate<T> fn, string fieldFix = "Node")
        {
            /// var dtInfos = infos.ToDataTable(rec => new object[] { infos }, "Info");
            /// var dtNodes = nodes.ToDataTable(rec => new object[] { nodes }, "Node");
            /// var dtParent = parent.ToDataTable(rec => new object[] { parent }, "Parent");
            var dts = new DataTable();
            // column names
            PropertyInfo[] propertyInfos = null;
            // Could add a check to verify that there is an element 0
            foreach (T rec in list)
            {
                // Use reflection to get property names, to create table, Only first time, others will follow
                if (propertyInfos == null)
                {
                    propertyInfos = rec.GetType().GetProperties();
                    foreach (var pi in propertyInfos)
                    {
                        var colType = pi.PropertyType;
                        if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>))) colType = colType.GetGenericArguments()[0];
                        dts.Columns.Add(new DataColumn(pi.Name, colType));
                    }
                }
                var dr = dts.NewRow();
                foreach (var pi in propertyInfos)
                {
                    dr[pi.Name] = pi.GetValue(rec, null) ?? DBNull.Value;
                }
                dts.Rows.Add(dr);
            }
            foreach (DataColumn dc in dts.Columns)
            {
                //var colName = string.Empty;
                //if (dc.ColumnName.Compare("PkId"))
                //{
                //    colName = fieldFix + "PkId";
                //}
                //else if (dc.ColumnName.Compare("ParentId"))
                //{
                //    colName = fieldFix + "ParentId";
                //}
                //else
                //{
                //    colName = fieldFix + dc.ColumnName;
                //}
                dc.ColumnName = fieldFix + dc.ColumnName;
            }
            return (dts);
        }
        public delegate object[] CreateRowDelegate<T>(T t);
    }
}
